//
// Created by hujin on 2020/11/8.
//

#ifndef C_MIPS_CMPLR_REGISTER_H
#define C_MIPS_CMPLR_REGISTER_H

#include <queue>
#include <iostream>

const int reg_func_ret = 2;  // fixed. due to syscall.
const int reg_func_call = 4; // fixed. due to syscall.
const int reg_func_call_cnt = 8 - 4; // fixed. due to syscall.
const int reg_store = 8;
const int reg_store_cnt = 16 - 8; // TODO : split to local & global register
const int reg_store_global = 8;
const int reg_store_global_cnt = 8;
const int reg_temp_0 = 25;
const int reg_sp = 29;
const int reg_fp = 30;
const int reg_ra = 31;
const int reg_cnt = 32;

#define getRegtx(x) ((x) + (reg_store))
#define getRegvx(x) ((x) + (reg_func_ret))
#define getRegax(x) ((x) + (reg_func_call))




//TODO
//需要的信息：全局寄存器分配：变量冲突图、权重表。输出：
//临时寄存器分配：变量冲突图


//算了。。。这个用在生成代码时维护吧
//上面这些放在analysis里生成，在ast里查询
//这里保障register的正确性
class Register{
    int occupied[reg_cnt] = {0};
    int usedTime[reg_cnt] = {0};
    int lastRequestReg = -1;
    int t = 0;
public:
    int requestGlobalReg(int desire){

        if(desire >= reg_store_global && desire < reg_store_global + reg_store_global_cnt && occupied[desire] == false){
            usedTime[desire] = t++;
            occupied[desire] = true;
            lastRequestReg = desire;
            return desire;
        }
        for(int i = 0; i < reg_store_global_cnt; i++){
            int j = i + reg_store_global;
            if(!occupied[j]) {
//                for(int i = 0; i < reg_cnt; i++){
//                    std::cout<<occupied[i]<<' ';
//                }
                usedTime[j] = t++;
                occupied[j] = true;
                //std::cout<<"use reg"<<j<<'\t\n';
                lastRequestReg = j;
                return j;
            }
        }
        return -1;
    }
    int requestNewReg(int desire) {
        if(desire >= reg_store && desire < reg_store + reg_store_cnt && occupied[desire] == false){
            usedTime[desire] = t++;
            occupied[desire] = true;
            lastRequestReg = desire;
            return desire;
        }
        for(int i = 0; i < reg_store_cnt; i++){
            int j = i + reg_store;
            if(!occupied[j]) {
//                for(int i = 0; i < reg_cnt; i++){
//                    std::cout<<occupied[i]<<' ';
//                }
                usedTime[j] = t++;
                occupied[j] = true;
                //std::cout<<"use reg"<<j<<'\t\n';
                lastRequestReg = j;
                return j;
            }
        }
        return -1;
    }
    void releaseReg(int i){
        occupied[i] = false;
        //std::cout<<"release reg"<<i<<'\t';
    }
    void markUsed(int reg){
        usedTime[reg] = t++;
    }

    int releaseAndReuseReg(){
        int mi = INT32_MAX, ans = 1;
        for(int i = 0; i < reg_store_cnt; i++) {
            int j = i + reg_store;
            if (occupied[j] && usedTime[j] < mi && j != lastRequestReg) {
                mi = usedTime[j], ans = j;
            }
        }
        //std::cout<<"release"<<ans<<std::endl;
        occupied[ans] =  1;
        lastRequestReg = ans;
        usedTime[ans] = t++;
        return ans;
    }

    Register *split(){
        auto *reg = new Register();
        for(int i=0; i < reg_cnt; i++){
            reg->occupied[i] = occupied[i];
            reg->usedTime[i] = usedTime[i];
        }
        reg->lastRequestReg = -1;
        reg->t = t;
        return reg;
    }
};










#endif //C_MIPS_CMPLR_REGISTER_H
